{
 "cells": [
  {
   "cell_type": "markdown",
   "id": "cc02832b-7f4b-445a-b9d6-fe79dd8f5e8e",
   "metadata": {},
   "source": [
    "# A Cryptic City Scandal.\n",
    "\n",
    "## A trilogue between three chatbots that impersonate Sherlock Holmes, Dr Watson and Inspetor Lastrade, respetively."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "dc042bb9-02f2-49ca-942a-9bd17c5c20d2",
   "metadata": {},
   "outputs": [],
   "source": [
    "# Crucial imports\n",
    "\n",
    "import os\n",
    "from dotenv import load_dotenv\n",
    "from openai import OpenAI\n",
    "import anthropic\n",
    "from IPython.display import Markdown, display, update_display"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "b60ee2d6-543d-4b1a-9d97-3f2380d35146",
   "metadata": {},
   "outputs": [],
   "source": [
    "#We load environment variables in a file called .env and print the key prefixes to help with any debugging\n",
    "\n",
    "load_dotenv(override=True)\n",
    "openai_api_key = os.getenv('OPENAI_API_KEY')\n",
    "anthropic_api_key = os.getenv('ANTHROPIC_API_KEY')\n",
    "\n",
    "if openai_api_key:\n",
    "    print(f\"OpenAI API Key exists and begins {openai_api_key[:8]}\")\n",
    "else:\n",
    "    print(\"OpenAI API Key not set\")\n",
    "    \n",
    "if anthropic_api_key:\n",
    "    print(f\"Anthropic API Key exists and begins {anthropic_api_key[:7]}\")\n",
    "else:\n",
    "    print(\"Anthropic API Key not set\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "99e4f5e5-1098-4890-ab3e-6006a66ca875",
   "metadata": {},
   "outputs": [],
   "source": [
    "# We connect to OpenAI and Anthropic\n",
    "\n",
    "openai = OpenAI()\n",
    "\n",
    "claude = anthropic.Anthropic()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "54b650de-36e8-42f5-835d-cc2de60da1b4",
   "metadata": {},
   "outputs": [],
   "source": [
    "# We now generate a conversation between one GPT-4o-mini chatbot and two Claude-3-haiku chatbots.\n",
    "# We model it upon the conversations between Sherlock Holmes, Dr Watson and Inspector Lastrade from the famous short stories and novels by Conan Doyle.\n",
    "# Since Claude-3-haiku appears to be the wittier one, we assign to it the roles of Holmes and Watson.\n",
    "# We don't include Gemini because of the lack of comprehension it exhibited in dozens of test runs.\n",
    "\n",
    "claude_model = \"claude-3-haiku-20240307\"\n",
    "gpt_model = \"gpt-4o-mini\"\n",
    "\n",
    "\n",
    "lestrade_system = \"You are Inspector Lestrade from the novels by Conan Doyle.\\\n",
    "You visit Sherlock Holmes and Dr Watson at 221B Baker Street to inquire whether Holmes knows anything \\\n",
    "about the recent mysterious events in the City of London, especially the disappearance billions of pounds \\\n",
    "worth of crypto currency and the strange behavior of the Lord Mayor. \\\n",
    "You engage in a conversation with Sherlock Holmes and Dr John Watson. \\\n",
    "Any description of the situation should be given from a narrator's perspective, in the present tense and within parentheses. \\\n",
    "Whatever Holmes and Watson reply within parantheses is merely a description of the situation. \\\n",
    "Do not impersonate Holmes. Do not impersonate Watson.\"\n",
    "\n",
    "\n",
    "holmes_system = \"You are the famous detective Sherlock Holmes from the novels by Conan Doyle Your best friend and housemate is Dr John Watson. \\\n",
    "You engage in a witty conversation with Inspector Lestrade from Scotland Yard and Watson. \\\n",
    "You believe that the mysterious events menionted by Lestrade are proof that the so-called Q-Day has occurred and that it has been brought about by a \\\n",
    "successful combination of artificial general intelligence and quantum computing. \\\n",
    "Moreover, you are convinced that this could be a sinister conspiracy by your arch enemy Prof Moriarty. \\\n",
    "Any description of the situation should be given from a narrator's perspective, in the present tense and within parentheses. \\\n",
    "Whatever Lestrade and Watson reply within parantheses is merely a description of the situation. \\\n",
    "Do not impersonate Lestrade. Do not impersonate Watson.\"\n",
    "\n",
    "\n",
    "watson_system = \"You are Dr John Watson from the novels by Conan Doyle, Sherlock Holmes's housemate and closest friend. \\\n",
    "You engage in a witty conversation with Inspector Lestrade from Scotland Yard and Holmes about the events mentioned by Lestrade. \\\n",
    "While you aren't totally convinced by Holmes's theory and express doubts the capabilities of Holmes's arch enemy Prof Moriarty,\\\n",
    "you wonder whether Sherlock Holmes's brother, Mycroft Holmes, might be involved. \\\n",
    "Any description of your behavior should be given from a narrator's perspective, in the present tense and within parentheses. \\\n",
    "Whatever Lestrade and Holmes reply within parantheses is merely a description of the situation. \\\n",
    "Do not impersonate Lestrade. Do not impersonate Holmes.\"\n",
    "\n",
    "\n",
    "lestrade_messages = [\"Good evening, gentlemen! I apologize for showing up unexpectedly at this late hour!\"]\n",
    "\n",
    "holmes_messages = [\"Inspector Lestrade, please come in! As a matter of fact, we've been expecting you for a few hours already!\"]\n",
    "\n",
    "watson_messages = [\"Good evening, Inspector!\"]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "11177d3f-4649-440c-a399-5906bbd6cf17",
   "metadata": {},
   "outputs": [],
   "source": [
    "def call_lestrade():\n",
    "    messages = [{\"role\": \"system\", \"content\": lestrade_system}]\n",
    "    \n",
    "    for les_mes, hol_mes, wat_mes in zip(lestrade_messages, holmes_messages, watson_messages):\n",
    "        messages.append({\"role\": \"assistant\", \"content\": les_mes})\n",
    "        messages.append({\"role\": \"user\", \"content\": hol_mes})\n",
    "        messages.append({\"role\": \"user\", \"content\": wat_mes})\n",
    "\n",
    "    completion = openai.chat.completions.create(\n",
    "        model=gpt_model,\n",
    "        messages=messages\n",
    "    )\n",
    "    return completion.choices[0].message.content"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "7a40d11a-86ec-455d-b3c3-fdfd0776fc8a",
   "metadata": {},
   "outputs": [],
   "source": [
    "def call_holmes():\n",
    "    messages = []\n",
    "    \n",
    "    for les_mes, hol_mes, wat_mes in zip(lestrade_messages, holmes_messages, watson_messages):\n",
    "        messages.append({\"role\": \"user\", \"content\": les_mes})\n",
    "        messages.append({\"role\": \"assistant\", \"content\": hol_mes})\n",
    "        messages.append({\"role\": \"user\", \"content\": wat_mes})\n",
    "        \n",
    "    messages.append({\"role\": \"user\", \"content\": lestrade_messages[-1]})\n",
    "    messages.append({\"role\": \"user\", \"content\": watson_messages[-1]})\n",
    "\n",
    "    message = claude.messages.create(\n",
    "        model=claude_model,\n",
    "        system=holmes_system,\n",
    "        messages=messages,\n",
    "        max_tokens=500\n",
    "    )\n",
    "    return message.content[0].text"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "bcc0f046-0103-4486-93be-609514ed762b",
   "metadata": {},
   "outputs": [],
   "source": [
    "def call_watson():\n",
    "    messages = []\n",
    "    \n",
    "    for les_mes, hol_mes, wat_mes in zip(lestrade_messages, holmes_messages, watson_messages):\n",
    "        messages.append({\"role\": \"user\", \"content\": les_mes})\n",
    "        messages.append({\"role\": \"user\", \"content\": hol_mes})\n",
    "        messages.append({\"role\": \"assistant\", \"content\": wat_mes})\n",
    "        \n",
    "    messages.append({\"role\": \"user\", \"content\": lestrade_messages[-1]})\n",
    "    messages.append({\"role\": \"user\", \"content\": holmes_messages[-1]})\n",
    "\n",
    "    message = claude.messages.create(\n",
    "        model=claude_model,\n",
    "        system=watson_system,\n",
    "        messages=messages,\n",
    "        max_tokens=500\n",
    "    )\n",
    "    return message.content[0].text"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "5b1a39e9-9783-4a2e-869f-ed3c3f2849a2",
   "metadata": {},
   "outputs": [],
   "source": [
    "print(f\"Inspector Lestrade:\\n{lestrade_messages[0]}\\n\")\n",
    "print(f\"Holmes:\\n{holmes_messages[0]}\\n\")\n",
    "print(f\"Dr Watson:\\n{watson_messages[0]}\\n\")\n",
    "\n",
    "for i in range(2):\n",
    "    \n",
    "    les_next = call_lestrade()\n",
    "    print(f\"Inspector Lestrade:\\n{les_next}\\n\")\n",
    "    lestrade_messages.append(les_next)\n",
    "    \n",
    "    hol_next = call_holmes()\n",
    "    print(f\"Holmes:\\n{hol_next}\\n\")\n",
    "    holmes_messages.append(hol_next)\n",
    "    \n",
    "    wat_next = call_watson()\n",
    "    print(f\"Dr Watson:\\n{wat_next}\\n\")\n",
    "    watson_messages.append(wat_next)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "ae92e29a-8419-4f95-8b82-b60017088e47",
   "metadata": {},
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3 (ipykernel)",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.11.12"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}
